package stmlib.examples;

import java.util.*;
import stmlib.ConcurrentStmMap;
import stmlib.Stm;
import stmlib.TransactionT;
import stmlib.Var;

/*
 * Benchmarks
 * @author Seun Osewa
 */
public class Test {
    static class Deadlock extends Thread {
        final Var<Integer> x;
        final Var<Integer> y;

        public Deadlock(Var<Integer> x, Var<Integer> y) { this.x = x; this.y = y; }

        public void run() {
            long l1 = System.currentTimeMillis();
            final Random rand = new Random();
            final TransactionT.V tt = new TransactionT.V(){public void atomicV(){
                final boolean dir = rand.nextBoolean();
                final Var<Integer> xx = (dir)?x:y;
                final Var<Integer> yy = (dir)?y:x;
                int cond = xx.get();
                int initial = yy.lock().get();
                if(cond != 2000000000) yy.set(initial + 1);
            }};

            for(int i = 0; i < 1000000; i++) {
                tt.execute(); //atomic operation. succeeds or fails.
            }
            long l2 = System.currentTimeMillis();
            System.out.println("Time Taken: " + new Long(l2-l1).toString()+ " x:" +
                 x.peek() + " y:" + y.peek() + " retries:" + Stm.retries + " ");
        }
        
        public static void bench() {
            final int N = 4;
            Var<Integer> a = new Var<Integer>(0);
            Var<Integer> b = new Var<Integer>(0);
            for(int i = 0; i < N; i++) { (new Deadlock(a, b)).start(); }
        }
    }

        public static final ConcurrentStmMap<Integer, Integer> cDict
              = new ConcurrentStmMap(500);

        public static class MapConcurrency extends Thread {
        //public static StmMap<Integer, Integer> cDict = new StmMap<Integer, Integer>();

        //= new ConcurrentStmMap<Integer, Integer>(1000);
        public static Var<Integer> threadsCompleted = new Var<Integer>(0);

        public void run() {
            long l1 = System.currentTimeMillis();
            final int N = 1000000;
            final Random rand = new Random();
            final int STEP = 5;

            final TransactionT.V tt = new TransactionT.V(){public void atomicV(){
                final int pos = rand.nextInt(1000);
                final Integer cur = cDict.lock(pos).get(pos);
                cDict.put(pos, (cur == null)? 1:cur+1);
            }};

            class UU extends TransactionT.V {
                public void atomicV(){ for (int j = ii; j<ii+STEP; j++) tt.execute(); }
                public int ii = 0;
            }
            final UU uu = new UU();
            
            for (int i=0; i<N; i+=STEP) {
                uu.ii = i;
                for (int j = i; j<i+STEP; j++) tt.execute();
                //uu.execute();
            }

            new TransactionT.V(){public void atomicV(){
                threadsCompleted.set(threadsCompleted.lock().get() + 1);
            }}.execute();

            long l2 = System.currentTimeMillis();
            System.out.println("Time Taken: " + ((l2-l1)/1000.0) + " Retries: " + Stm.retries);
        }

        public static void bench() {
            final int N = 64;
            for(int i=0; i<N; i++)(new MapConcurrency()).start();
            do {
                try { Thread.sleep(125); } catch (InterruptedException e){}
                if (threadsCompleted.peek() == N) {
                    new TransactionT.V(){public void atomicV(){
                        int sum = 0;
                        for (int n: cDict.values()) { sum += n; }
                        Stm.println("FINISHED! " + sum + " increments.");
                    }}.execute();
                    break;
                }
            } while(true);
        }
    }

    public static void simple() {
        long l1 = System.currentTimeMillis();
        final Var<Integer> v = new Var<Integer>(0);

        TransactionT tt = new TransactionT.V(){public void atomicV(){
           v.set(v.lock().get() + 1) ;
        }};
        
        for (int i = 0; i<10000000; i++) tt.execute();
        long l2 = System.currentTimeMillis();
        System.out.println(l2-l1);
    }
    public static void main(String[] args) { MapConcurrency.bench(); }
}